logo头像
Snippet 博客主题

ExpandableListView实现商品列表折叠

本文于646天之前发表,文中内容可能已经过时。

简介

在日常的开发中,有可能会遇到需要一些可以展开的列表,比如QQ的好友列表,电商的购物车折叠显示。Android也给我们提供ExpandableListView类,完美实现这样类似的需求, 极大的方便了我们开发。结合之前的项目我们做一个简单的讲解。
首先懒看一下最终的实现效果:
这里写图片描述
使用到的第三方框架:
AndroidAutoLayout 屏幕适配框架

代码

首先是布局需要用一个ExpandableListView,配合adapter就能实现上面额效果,直接上代码。
activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<com.zhy.autolayout.AutoLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.zhy.autolayout.AutoLinearLayout
android:id="@+id/ll_title_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ec0f38"
android:orientation="vertical">
<com.zhy.autolayout.AutoFrameLayout
android:layout_width="match_parent"
android:layout_height="88px">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:gravity="center"
android:text="优惠套餐"
android:textColor="#ffffff"
android:textSize="32px" />
<com.zhy.autolayout.AutoLinearLayout
android:id="@+id/ll_back"
android:layout_width="100px"
android:layout_height="match_parent"
android:clickable="true"
android:gravity="center">
<ImageView
android:id="@+id/iv_back"
android:layout_width="44px"
android:layout_height="44px"
android:layout_gravity="center_vertical"
android:src="@mipmap/icon_back" />
</com.zhy.autolayout.AutoLinearLayout>
</com.zhy.autolayout.AutoFrameLayout>
</com.zhy.autolayout.AutoLinearLayout>
</android.support.design.widget.AppBarLayout>
<ExpandableListView
android:id="@+id/elv_collocation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#eeeff3"
android:divider="#eeeff3"
android:dividerHeight="0dp"
android:groupIndicator="@null"
android:listSelector="@null" />
</com.zhy.autolayout.AutoLinearLayout>

MainActivity.java
默认展开第一个,collocation.expandGroup(0);当然更好的写法是将数据写到Controller中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class MainActivity extends AppCompatActivity {
private ExpandableListView elv_collocation;
private List<CollocationPackageBean> collocationList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
elv_collocation = (ExpandableListView) findViewById(R.id.elv_collocation);
initData();
}
private void initData() {
collocationList = new ArrayList<>();
CollocationPackageBean collocation_1 = new CollocationPackageBean();
CollocationPackageBean collocation_2 = new CollocationPackageBean();
collocation_1.setTotalPrice(new BigDecimal(897));
collocation_1.setDiscountFee(new BigDecimal(20));
collocation_1.setName("818国货套餐3");
List<CollocationPackageBean.CollocationSkuBean> goodsList_1 = new ArrayList<>();
goodsList_1.add(new CollocationPackageBean.CollocationSkuBean("Meizu/魅族 魅蓝 note3 全网通 手机 银白 16GB", "http://img11.hqbcdn.com/product/07/0a/070ac7abd57c6d9251d89547f3d62501.jpg"));
goodsList_1.add(new CollocationPackageBean.CollocationSkuBean("VR PLUS 智能眼镜vr虚拟现实头盔 3D沉浸式 暴风魔镜 vr plus 智能头盔 白色", "http://img15.hqbcdn.com/product/c6/10/c610075082199955a8d5dcf2aa765b17.jpg"));
collocation_1.setCollocationSkuDoList(goodsList_1);
collocation_2.setTotalPrice(new BigDecimal(1034));
collocation_2.setDiscountFee(new BigDecimal(26));
collocation_2.setName("超值套餐");
List<CollocationPackageBean.CollocationSkuBean> goodsList_2 = new ArrayList<>();
goodsList_2.add(new CollocationPackageBean.CollocationSkuBean("Meizu/魅族 魅蓝 note3 全网通 手机 银白 16GB", "http://img11.hqbcdn.com/product/07/0a/070ac7abd57c6d9251d89547f3d62501.jpg"));
goodsList_2.add(new CollocationPackageBean.CollocationSkuBean("Uka/优加 Meizu/魅族 魅蓝 note3全覆盖全屏钢化玻璃膜 白色", "http://img8.hqbcdn.com/product/9c/15/9c15571aa92905ea1edafb0a288f1ebb.jpg"));
goodsList_2.add(new CollocationPackageBean.CollocationSkuBean("SanDisk/闪迪 至尊高速MicroSDHC-TF移动存储卡 Class10-48MB/S 升级版 16G", "http://img14.hqbcdn.com/product/29/cd/29cda69f5036b38454b6592f96fde774.jpg"));
goodsList_2.add(new CollocationPackageBean.CollocationSkuBean("Huawei/华为 AM116 金属耳机 三键线控耳机 尊爵版", "http://img9.hqbcdn.com/product/0a/90/0a905d9988c91fb0625d9ee44377c8e0.jpg"));
goodsList_2.add(new CollocationPackageBean.CollocationSkuBean("Lesimo/梵简 初见系列10000毫安充电宝 手机平板通用 移动电源 黑色", "http://img11.hqbcdn.com/product/67/3a/673ac0343758ce64e97c2d9986cbbef3.jpg"));
collocation_2.setCollocationSkuDoList(goodsList_2);
collocationList.add(collocation_1);
collocationList.add(collocation_2);
elv_collocation.setAdapter(new CollocationListAdapter(this, elv_collocation, collocationList));
elv_collocation.expandGroup(0);
}
}

CollocationListAdapter.java
CollocationListAdapter负责数据的填充,主要注意两个方法:getGroupView和getChildView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
public class CollocationListAdapter extends BaseExpandableListAdapter {
private LayoutInflater inflater;
private Context context;
private ExpandableListView elv_collocation;
private List<CollocationPackageBean> data;
public CollocationListAdapter(Context context, ExpandableListView elv_collocation, List<CollocationPackageBean> data) {
this.context = context;
this.elv_collocation = elv_collocation;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.data = data;
}
@Override
public int getGroupCount() {
return data.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return data.get(groupPosition).getCollocationSkuDoList().size();
}
@Override
public Object getGroup(int groupPosition) {
return data.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return data.get(groupPosition).getCollocationSkuDoList().get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;//如果子条目需要响应click事件,必需返回true
}
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
ParentViewHolder parentViewHolder;
if (null == convertView) {
convertView = inflater.inflate(R.layout.collocation_list_item_parent, parent, false);
parentViewHolder = new ParentViewHolder(convertView);
convertView.setTag(parentViewHolder);
AutoUtils.auto(convertView);
} else {
parentViewHolder = (ParentViewHolder) convertView.getTag();
}
CollocationPackageBean collocationPackageBean = data.get(groupPosition);
parentViewHolder.tv_collocation_name.setText(TextUtils.isEmpty(collocationPackageBean.getName()) ? "优惠套餐" : collocationPackageBean.getName());
parentViewHolder.tv_save_text.setText("立省¥" + collocationPackageBean.getDiscountFee());
parentViewHolder.iv_status.setImageResource(isExpanded ? R.mipmap.icon_top : R.mipmap.icon_bottom);
parentViewHolder.v_space.setVisibility(isExpanded ? View.GONE : View.VISIBLE);
parentViewHolder.hsv_goods_list.setVisibility(isExpanded ? View.GONE : View.VISIBLE);
parentViewHolder.hsv_goods_list.setFocusable(false);//设置后解决套餐无法正常展开的bug
if (!isExpanded) {
//设置套餐折叠时显示套餐商品的图片
initGoodsImage(collocationPackageBean, parentViewHolder, groupPosition);
}
return convertView;
}
@Override
public View getChildView(final int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ChildViewHolder childViewHolder;
if (null == convertView) {
convertView = inflater.inflate(R.layout.collocation_list_item_child, parent, false);
childViewHolder = new ChildViewHolder(convertView);
convertView.setTag(childViewHolder);
AutoUtils.auto(convertView);
} else {
childViewHolder = (ChildViewHolder) convertView.getTag();
}
final CollocationPackageBean.CollocationSkuBean collocationSkuBean = data.get(groupPosition).getCollocationSkuDoList().get(childPosition);
childViewHolder.sdv_goods_img.setImageURI(Uri.parse(collocationSkuBean.getImageMd5()));
childViewHolder.tv_goods_title.setText(collocationSkuBean.getSkuTitle());
childViewHolder.ll_root_view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//进入商品详情页操作
}
});
if (childPosition == data.get(groupPosition).getCollocationSkuDoList().size() - 1) {
//当前套餐的最后一个商品
childViewHolder.ll_bottom.setVisibility(View.VISIBLE);
childViewHolder.tv_collocation_price.setText(data.get(groupPosition).getTotalPrice().toString());
childViewHolder.tv_add_cart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//把套餐商品加入购物车操作
}
});
} else {
childViewHolder.ll_bottom.setVisibility(View.GONE);
}
return convertView;
}
class ParentViewHolder {
private View v_space;
private ImageView iv_status;
private HorizontalScrollView hsv_goods_list;
private TextView tv_collocation_name, tv_save_text;
private ParentViewHolder (View view) {
v_space = view.findViewById(R.id.v_space);
iv_status = (ImageView) view.findViewById(R.id.iv_status);
hsv_goods_list = (HorizontalScrollView) view.findViewById(R.id.hsv_goods_list);
tv_collocation_name = (TextView) view.findViewById(R.id.tv_collocation_name);
tv_save_text = (TextView) view.findViewById(R.id.tv_save_text);
}
}
private class ChildViewHolder {
private SimpleDraweeView sdv_goods_img;
private LinearLayout ll_bottom, ll_root_view;
private TextView tv_add_cart, tv_goods_title, tv_collocation_price;
private ChildViewHolder (View view) {
sdv_goods_img = (SimpleDraweeView) view.findViewById(R.id.sdv_goods_img);
ll_bottom = (LinearLayout) view.findViewById(R.id.ll_bottom);
ll_root_view = (LinearLayout) view.findViewById(R.id.ll_root_view);
tv_add_cart = (TextView) view.findViewById(R.id.tv_add_cart);
tv_goods_title = (TextView) view.findViewById(R.id.tv_goods_title);
tv_collocation_price = (TextView) view.findViewById(R.id.tv_collocation_price);
}
}
/**
* 初始化并设置套餐折叠时的所有商品图片
* @param collocationPackageBean
* @param parentViewHolder
* @param groupPosition
*/
private void initGoodsImage(CollocationPackageBean collocationPackageBean,
ParentViewHolder parentViewHolder, final int groupPosition) {
View collocationView;
SimpleDraweeView sdv_cart_image;
RelativeLayout rl_middle;
LinearLayout rootview = new LinearLayout(context);
for (int i = 0, len = collocationPackageBean.getCollocationSkuDoList().size(); i < len; i++) {
collocationView = inflater.inflate(R.layout.item_gift_img, null);
sdv_cart_image = (SimpleDraweeView) collocationView.findViewById(R.id.sdv_cart_image);
rl_middle = (RelativeLayout) collocationView.findViewById(R.id.rl_middle);
sdv_cart_image.setImageURI(Uri.parse(collocationPackageBean.getCollocationSkuDoList().get(i).getImageMd5()));
rl_middle.setVisibility(View.INVISIBLE);
collocationView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//手动实现展开操作
elv_collocation.expandGroup(groupPosition);
}
});
AutoUtils.auto(collocationView);
rootview.addView(collocationView);
}
parentViewHolder.hsv_goods_list.removeAllViews();
parentViewHolder.hsv_goods_list.addView(rootview);
}
}

collocation_list_item_child.xml
子布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<com.zhy.autolayout.AutoLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:clickable="true"
android:orientation="vertical">
<com.zhy.autolayout.AutoLinearLayout
android:id="@+id/ll_root_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_me_bg_item"
android:paddingBottom="28px"
android:paddingLeft="24px"
android:paddingRight="24px"
android:paddingTop="30px">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/sdv_goods_img"
android:layout_width="120px"
android:layout_height="120px"
android:background="@drawable/shape_cart_goods_border"
android:padding="1dp"
fresco:placeholderImage="@mipmap/icon_loading_bg" />
<TextView
android:id="@+id/tv_goods_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20px"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#222222"
android:textSize="30px" />
<View
android:layout_width="118px"
android:layout_height="1px" />
<ImageView
android:layout_width="18px"
android:layout_height="28px"
android:src="@mipmap/icon_right" />
</com.zhy.autolayout.AutoLinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="24px"
android:background="#dddddd" />
<com.zhy.autolayout.AutoLinearLayout
android:id="@+id/ll_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.zhy.autolayout.AutoLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingLeft="24px"
android:paddingRight="24px"
android:paddingTop="20px">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="套餐价格:"
android:textColor="#888888"
android:textSize="30px" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20px"
android:text="¥"
android:textColor="#ec0f38"
android:textSize="22px" />
<TextView
android:id="@+id/tv_collocation_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ec0f38"
android:textSize="30px" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/tv_add_cart"
android:layout_width="180px"
android:layout_height="50px"
android:background="@drawable/selector_add_cart_red_btn"
android:gravity="center"
android:text="加入购物车"
android:textColor="@drawable/selector_add_cart_red_tv"
android:textSize="28px" />
</com.zhy.autolayout.AutoLinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="20px"
android:layout_marginTop="20px"
android:background="#eeeff3" />
</com.zhy.autolayout.AutoLinearLayout>
</com.zhy.autolayout.AutoLinearLayout>

collocation_list_item_parent.xml
父布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<com.zhy.autolayout.AutoLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
android:paddingTop="20px">
<com.zhy.autolayout.AutoLinearLayout
android:layout_width="match_parent"
android:layout_height="50px"
android:layout_marginBottom="30px"
android:gravity="center_vertical"
android:paddingLeft="24px"
android:paddingRight="24px">
<TextView
android:id="@+id/tv_collocation_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#222222"
android:textSize="30px" />
<TextView
android:id="@+id/tv_save_text"
android:layout_width="wrap_content"
android:layout_height="40px"
android:layout_marginLeft="20px"
android:background="@drawable/shape_save_money"
android:gravity="center"
android:paddingLeft="18px"
android:paddingRight="18px"
android:textColor="#ffffff"
android:textSize="24px" />
<View
android:layout_width="0dp"
android:layout_height="1px"
android:layout_weight="1" />
<ImageView
android:id="@+id/iv_status"
android:layout_width="28px"
android:layout_height="18px"
android:layout_gravity="right|center_vertical"
android:src="@mipmap/icon_top" />
</com.zhy.autolayout.AutoLinearLayout>
<HorizontalScrollView
android:id="@+id/hsv_goods_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="24px"
android:scrollbars="none" />
<View
android:id="@+id/v_space"
android:layout_width="match_parent"
android:layout_height="20px"
android:layout_marginTop="20px"
android:background="#eeeff3"
android:visibility="gone" />
</com.zhy.autolayout.AutoLinearLayout>

这样就基本实现了。源码地址

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

上一篇